# 下载并读取数据
from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# MNIST数据分为三部分：训练数据（mnist.train）的55,000个数据点，
# 测试数据（mnist.test）的10,000个点和验证数据（mnist.validation）的5,000个点。
# 训练集和测试集都包含图像及其相应的标签;
# 例如训练图像是mnist.train.images 和训练标签是mnist.train.labels。


# 创建符号变量,784是图片像素
x = tf.placeholder(tf.float32, [None, 784])

# placeholder是TensorFlow运行计算时输入的值。
# 希望能够输入任意数量的MNIST图像，每个图像被平面化成784维向量。
# 我们把它表示成浮点数的二维张量[None, 784]。
# （None意味着一个维度可以是任意长度的。）

# 也需要我们的模型的权重和偏见
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

# Variable是在TensorFlow交互操作图中的可修改张量。
# 它可以被使用，甚至被计算修改。
# 对于机器学习应用程序，通常具有的模型参数是Variable。
# 通过给出tf.Variable初始值创建这些Variable
# 在这种情况下，这两个W和b被初始化为充满零的张量。

# 注意，W它的形状是[784，10]，因为我们想用它乘以784维图像矢量，
# 以产生差分类证据的10维向量。10是结果个数，即0-9.
# b具有[10]的形状，所以我们可以将其添加到输出

# 实现我们的模型。只需要一行来定义它
# y = softmax(W*x+b)
y = tf.nn.softmax(tf.matmul(x, W) + b)

# 用W乘x表示为tf.matmul(x, W)。
# 当我们在我们的方程中乘以它们时，就会翻转W*x，
# 作为一个小技巧来处理x与多个输入二维张量。
# 然后我们添加b，最后申请tf.nn.softmax。

# 一个非常常见的，非常好的函数来确定模型的损失被称为“交叉熵”
# Hy'(y)=-y'*log(y)
# y是我们预测的概率分布， y'是真正的分布（带有数字标签的单向矢量）

# 为了实现交叉熵，我们需要首先添加一个新的占位符来输入正确的答案
y_ = tf.placeholder(tf.float32, [None, 10])

# 实现交叉熵函数,-y'*log(y)
# cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))

# 首先，tf.log计算每个元素的对数y。
# 接下来，我们将每个元素y_与相应的元素相乘tf.log(y)。
# 然后 tf.reduce_sum，由于reduction_indices=[1]参数的原因，在y的第二维中添加元素 。
# 最后，tf.reduce_mean计算批处理中所有示例的平均值。

# 请注意，在源代码中，我们不使用这个公式，因为它在数值上是不稳定的。
# 相反，我们应用 tf.nn.softmax_cross_entropy_with_logits的非标准化logits
# （例如，我们称之为softmax_cross_entropy_with_logits上tf.matmul(x, W) + b），
# 因为这个数值上更稳定的内部函数计算SOFTMAX激活。
# 在你的代码中，请考虑使用tf.nn.softmax_cross_entropy_with_logits 。

# 自动使用 反向传播算法来有效地确定您的变量如何影响您要求它最小化的损失
# 然后它可以应用你选择的优化算法来修改变量并减少损失。
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

# 可以通过以下方式启动模型InteractiveSession：
sess = tf.InteractiveSession()

# 首先必须创建一个操作来初始化我们创建的变量：
tf.global_variables_initializer().run()

# 让我们训练 - 我们将运行1000次的训练步骤
for _ in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

# 循环的每一步，我们从我们的训练集中获得一百个随机数据点的“批次”。
# 我们运行train_step批量数据来取代placeholder。

# 那么，首先让我们弄清楚我们预测了正确的标签。
# tf.argmax 是一个非常有用的函数，它可以使您沿某个轴在张量中输入最高的索引。
# 例如，tf.argmax(y,1)我们的模型认为是每个输入最有可能的标签，
# 而tf.argmax(y_,1)正确的标签。
# 我们可以tf.equal用来检查我们的预测是否符合事实。

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))

# 这给了我们一个布尔的列表。为了确定什么分数是正确的，我们转换为浮点数，然后取平均值。
# 例如， [True, False, True, True]会变成[1,0,1,1]哪个会变成0.75。

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

# 最后，我们要求我们的测试数据的准确性

print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
